package main

import (
	"encoding/binary"
	"flag"
	"fmt"
	"log"
	"net"
	"syscall"
	"time"
)

const (
	IPPROTO_OSPF   = 89
	OSPFVersion    = 2
	OSPFHelloType  = 1
	OSPFHeaderLen  = 24
	HelloPacketLen = 20
	IPHeaderLen    = 20
)

type OSPFClient struct {
	fd         int    // 原始socket文件描述符
	sourceIP   net.IP // 源IP地址
	destIP     net.IP // 目标IP地址
	routerID   uint32 // 路由器ID
	ifaceIndex int    // 网络接口索引
}

// 创建新的OSPF客户端
func NewOSPFClient(sourceIP, destIP string, ifaceName string) (*OSPFClient, error) {
	// 创建原始socket
	fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, IPPROTO_OSPF)
	if err != nil {
		return nil, fmt.Errorf("创建socket失败: %v", err)
	}

	// 设置socket选项，允许IP头部自定义
	err = syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
	if err != nil {
		syscall.Close(fd)
		return nil, fmt.Errorf("设置socket选项失败: %v", err)
	}

	// 获取网络接口索引
	iface, err := net.InterfaceByName(ifaceName)
	if err != nil {
		syscall.Close(fd)
		return nil, fmt.Errorf("获取网络接口失败: %v", err)
	}

	srcIP := net.ParseIP(sourceIP)
	if srcIP == nil {
		syscall.Close(fd)
		return nil, fmt.Errorf("无效的源IP地址")
	}

	dstIP := net.ParseIP(destIP)
	if dstIP == nil {
		syscall.Close(fd)
		return nil, fmt.Errorf("无效的目标IP地址")
	}

	return &OSPFClient{
		fd:         fd,
		sourceIP:   srcIP.To4(),
		destIP:     dstIP.To4(),
		routerID:   binary.BigEndian.Uint32(srcIP.To4()),
		ifaceIndex: iface.Index,
	}, nil
}

// 计算IP校验和
func calculateIPChecksum(data []byte) uint16 {
	var sum uint32
	for i := 0; i < len(data); i += 2 {
		sum += uint32(data[i]) << 8
		if i+1 < len(data) {
			sum += uint32(data[i+1])
		}
	}
	sum = (sum >> 16) + (sum & 0xffff)
	sum = sum + (sum >> 16)
	return ^uint16(sum)
}

// 创建IP头部
func (c *OSPFClient) createIPHeader(totalLen uint16) []byte {
	ipHeader := make([]byte, IPHeaderLen)

	// IP版本(4)和头部长度(5)
	ipHeader[0] = 0x45
	// 服务类型
	ipHeader[1] = 0
	// 总长度
	binary.BigEndian.PutUint16(ipHeader[2:4], totalLen)
	// 标识
	binary.BigEndian.PutUint16(ipHeader[4:6], uint16(time.Now().UnixNano()))
	// 标志和片偏移
	binary.BigEndian.PutUint16(ipHeader[6:8], 0)
	// TTL
	ipHeader[8] = 1
	// 协议(OSPF=89)
	ipHeader[9] = 89
	// 校验和(先置0)
	binary.BigEndian.PutUint16(ipHeader[10:12], 0)
	// 源IP
	copy(ipHeader[12:16], c.sourceIP.To4())
	// 目标IP
	copy(ipHeader[16:20], c.destIP.To4())

	// 计算校验和
	checksum := calculateIPChecksum(ipHeader)
	binary.BigEndian.PutUint16(ipHeader[10:12], checksum)

	return ipHeader
}

// 创建OSPF Hello包
func (c *OSPFClient) createOSPFHello(data string) []byte {
	// OSPF头部(24字节) + Hello包(20字节)
	totalLen := OSPFHeaderLen + HelloPacketLen
	packet := make([]byte, totalLen)

	// OSPF Header
	packet[0] = OSPFVersion
	packet[1] = OSPFHelloType
	binary.BigEndian.PutUint16(packet[2:4], uint16(totalLen))
	binary.BigEndian.PutUint32(packet[4:8], c.routerID)
	binary.BigEndian.PutUint32(packet[8:12], 0) // Area ID
	// Checksum位置：packet[12:14]
	binary.BigEndian.PutUint16(packet[14:16], 0) // Authentication Type
	binary.BigEndian.PutUint64(packet[16:24], 0) // Authentication

	// Hello Packet
	binary.BigEndian.PutUint32(packet[24:28], 0xffffff00) // Network Mask
	binary.BigEndian.PutUint16(packet[28:30], 10)         // Hello Interval
	packet[30] = 0x02                                     // Options
	packet[31] = 1                                        // Priority

	// 在Dead Interval字段中嵌入数据
	dataBytes := []byte(data)
	if len(dataBytes) > 4 {
		dataBytes = dataBytes[:4] // 限制数据长度为4字节
	}
	copy(packet[32:36], dataBytes)

	// DR和BDR
	binary.BigEndian.PutUint32(packet[36:40], 0)
	binary.BigEndian.PutUint32(packet[40:44], 0)

	// 计算OSPF校验和
	checksum := calculateIPChecksum(packet)
	binary.BigEndian.PutUint16(packet[12:14], checksum)

	return packet
}

// 发送数据
func (c *OSPFClient) SendData(data string) error {
	ospfPacket := c.createOSPFHello(data)
	ipHeader := c.createIPHeader(uint16(IPHeaderLen + len(ospfPacket)))

	// 组合完整的数据包
	packet := append(ipHeader, ospfPacket...)

	// 准备目标地址结构
	addr := syscall.SockaddrInet4{
		Port: 0,
		Addr: [4]byte{c.destIP[0], c.destIP[1], c.destIP[2], c.destIP[3]},
	}

	// 发送数据
	err := syscall.Sendto(c.fd, packet, 0, &addr)
	if err != nil {
		return fmt.Errorf("发送数据失败: %v", err)
	}

	return nil
}

// 关闭客户端
func (c *OSPFClient) Close() {
	if c.fd != 0 {
		syscall.Close(c.fd)
	}
}

func main() {
	sourceIP := flag.String("source", "192.168.0.243", "源IP地址")
	destIP := flag.String("dest", "192.168.0.245", "目标IP地址(默认: OSPF组播地址)")
	iface := flag.String("i", "ens34", "网络接口名称")
	data := flag.String("data", "hell", "要发送的数据")
	interval := flag.Int("interval", 5, "发送间隔(秒)")
	flag.Parse()

	if *sourceIP == "" || *iface == "" {
		log.Fatal("请指定源IP地址和网络接口")
	}

	client, err := NewOSPFClient(*sourceIP, *destIP, *iface)
	if err != nil {
		log.Fatalf("创建客户端失败: %v", err)
	}
	defer client.Close()

	log.Printf("开始发送数据到 %s...", *destIP)

	// 循环发送数据
	ticker := time.NewTicker(time.Duration(*interval) * time.Second)
	defer ticker.Stop()

	for range ticker.C {
		err = client.SendData(*data)
		if err != nil {
			log.Printf("发送数据失败: %v", err)
			continue
		}
		log.Printf("已发送数据: %s", *data)
	}
}
